#include "../include/modules/interface.h"
#include "../include/modules/coordinates.h"
#include "../include/engine/system.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Tools* initTools(GLuint *textureT, GLuint *textureM, List *listTower, List *listMonster, Player *player, Map *map, TwBar *menu, TwBar *monster, TwBar **tower, int *loop, int *replay){
	if(textureT == NULL || textureM == NULL || listTower == NULL || listMonster == NULL || player == NULL || map == NULL){
		fprintf(stderr, "initTools::Un des pointeur n'existe pas\n");
		return NULL;
	}
	Tools *tools = (Tools *)malloc(sizeof(Tools));
	if(tools == NULL){
		fprintf(stderr, "tools à mal été malloc.\n");
		return NULL;
	}
	tools->textureT = textureT;
	tools->textureM = textureM;
	tools->listTower = listTower;
	tools->listMonster = listMonster;
	tools->player = player;
	tools->map = map;
	tools->menu = menu;
	tools->monster = monster;
	tools->tower = tower;
	tools->priceRocket = 250;
	tools->priceHybrid = 200;
	tools->priceLaser = 400;
	tools->priceMachineGun = 500;
	tools->loop = loop;
	tools->replay = replay;

	return tools;
}

MenuITD* initMenuITD(List itds){
	if(itds == NULL){
		fprintf(stderr, "initMenuITD::La liste n'existe pas.\n");
		return NULL;
	}
	MenuITD *mITD = (MenuITD *)malloc(sizeof(MenuITD));
	if(mITD == NULL){
		fprintf(stderr, "menuITD a mal été malloc.\n");
		return NULL;
	}
	mITD->itds = itds;
	mITD->itd = "None\0";

	return mITD;
}

void initAntTwBar(unsigned int width, unsigned int height){
	// Initialize AntTweakBar
    TwInit(TW_OPENGL, NULL);
  	// Tell the window size to AntTweakBarTwDefineEnum
    TwWindowSize(width, height);
}

void createTwBar(TwBar **bar, char* name){
	*bar = TwNewBar(name);
}

void positionTwBar(unsigned int w_width, TwBar* bar){ // a modifier pour un barMenu, barMonster & barTower
	CoordSDL coordTmp;
	coordTmp.x = w_width*3/4;
	coordTmp.y = 0;

	int pos[3];
	pos[0] = coordTmp.x;
	pos[1] = coordTmp.y;

	TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
}

void positionPopUpTower(Tower *tower, TwBar* bar, int w_height, int w_width){ // Pop up tower
	CoordSDL coordTmp;
	coordTmp = coordOpenGLtoCoordSDL(tower->coord, w_height, w_width);

	int pos[3];
	pos[0] = coordTmp.x + 25;
	pos[1] = coordTmp.y - 10;

	TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
}

void positionPopUpMonster(Monster *monster, TwBar* bar, int w_height, int w_width){ // Pop up monster
	if(monster == NULL){
		return;
	}
	CoordSDL coordTmp;
	coordTmp = coordOpenGLtoCoordSDL(monster->pos, w_height, w_width);

	int pos[3];
	pos[0] = coordTmp.x + 25;
	pos[1] = coordTmp.y - 10;

	TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
}

void sizeTwBar(unsigned int w_width, unsigned int w_height, TwBar *bar){ // uniquement pour une barMenu
	int size[3];
	size[0] = (w_width*1/4);
	size[1] = w_height;
	TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2, size);
}

void TW_CALL setSelectTower(const void *value, void *clientData){
	int *v = (int *)value;
	Tools *tools = (Tools *)clientData;
	if(*v != 0){
		foreachList(node, *(tools->listTower)){ // Permet d'interdire le stack de construction de tours.
			Tower *t = (Tower *)node->data;
			if(t->isSet == 0){
				fprintf(stderr, "Veuillez d'abord placer votre tour selectionne.\n");
				return;
			}
		}
	}
    switch(*v){
    	case 0:
    		tools->player->constructMode = 0;
    		foreachList(node, *(tools->listTower)){ // Permet d'interdire le stack de construction de tours.
				Tower *t = (Tower *)node->data;
				if(t->isSet == 0){
					*(tools->listTower) = deleteTower(t, (tools->listTower));	//On supprime la derniere tour selectionné (non placée)
				}
			}
    		break;
    	case ROCKET:
    		*(tools->listTower) = buyTower(tools->player, *(tools->listTower), ROCKET, &(tools->textureT[0]), tools->player->param.w_width, tools->player->param.w_height, tools->map->squareDrew.nbFragSquare, tools->map->squareDrew.coordGL);
    		break;
    	case HYBRID:
    		*(tools->listTower) = buyTower(tools->player, *(tools->listTower), HYBRID, &(tools->textureT[1]), tools->player->param.w_width, tools->player->param.w_height, tools->map->squareDrew.nbFragSquare, tools->map->squareDrew.coordGL);
    		break;
    	case LASER:
    		*(tools->listTower) = buyTower(tools->player, *(tools->listTower), LASER, &(tools->textureT[2]), tools->player->param.w_width, tools->player->param.w_height, tools->map->squareDrew.nbFragSquare, tools->map->squareDrew.coordGL);
    		break;
    	case MACHINEGUN:
    		*(tools->listTower) = buyTower(tools->player, *(tools->listTower), MACHINEGUN, &(tools->textureT[3]), tools->player->param.w_width, tools->player->param.w_height, tools->map->squareDrew.nbFragSquare, tools->map->squareDrew.coordGL);
    		break;
    	default:
    		break;
    }
}

void TW_CALL getSelectTower(void *value, void *clientData){
	Tools *tools = (Tools *)clientData;
	*(int *)value = 0;
	lastList(node, *(tools->listTower)){
        *(int *)value = getTowerType(node->data);
    }
}

void TW_CALL setChooseITDCB(const void *value, void *clientData){
	int *v = (int *)value;
	MenuITD *menuItd = (MenuITD *)clientData;
	Node *temp = menuItd->itds;
	int i = 0;
	while(i != *v){
		if(temp->next != NULL){
			temp = temp->next;
			i++;
		}else{
			fprintf(stderr, "setChooseITDCB::Erreur temp->next est NULL.\n");
			return;
		}
	}
	menuItd->itd = (char *)temp->data;
}

void TW_CALL getChooseITDCB(void *value, void *clientData){
	MenuITD *menuItd = (MenuITD *)clientData;
	char *itd = (char *)menuItd->itd;
	Node *temp = menuItd->itds;
	int i = 0;
	if(strstr(itd,"None") == NULL){
		while(temp->data != itd){
			if(temp->next != NULL){
				temp = temp->next;
				i++;
			}else{
				fprintf(stderr, "getChooseITDCB::Erreur temp->next est NULL.\n");
				return;
			}
		}
	}
	*(int *)value = i;
}

void TW_CALL nextWaveCB(void *clientData){
	Tools* t= (Tools *)clientData;
	if((winWave(*(t->listMonster)) == 1 && t->map->wave==10) || t->player->lvl == 0){
		t->player->lvl++;
		t->map->wave = 0;
	}
}

void TW_CALL playCB(void *clientData){
	int *start = (int *)clientData;
	*start = 1;
}

void TW_CALL replayCB(void *clientData){
	Tools *t = (Tools *)clientData;
	*(t->replay) = 1;
	*(t->loop) = 0;
}

void TW_CALL ruleCB(void *clientData){
	TwBar *rule = (TwBar *)clientData;
	int iconified; // 128 chars max
	TwGetParam(rule, NULL, "iconified", TW_PARAM_INT32, 1, &iconified);
	if(iconified){
		TwSetParam(rule, NULL, "iconified", TW_PARAM_CSTRING, 1, "false");
	}
	else{
		TwSetParam(rule, NULL, "iconified", TW_PARAM_CSTRING, 1, "true");
	}
}

void TW_CALL deleteTowerCB(void *clientData){
	Tools *tools = (Tools *)clientData;
	foreachList(node, *tools->listTower){
		Tower *tower = (Tower *)node->data;
        if(tower->select == 1){
        	Square testSquareTower = findSquare(tower->coord, tools->map->squareTab, tools->map->nbSquare);
        	int i = 0;
		    while(i<tools->map->nbSquare){
		        if((testSquareTower.coordGL.x - (tools->map->squareTab[i].coordGL.x))<EPSILON && (testSquareTower.coordGL.y - (tools->map->squareTab[i].coordGL.y))<EPSILON){
		            tools->map->squareTab[i].availability = 1;
		            break;
		        }
		        i++;
		    }
        	int money = (int)((tower->price)/2);
        	setMoneyPlayer(tools->player, money);
        	TwDeleteBar(*tools->tower);
            *tools->tower = NULL;
        	deleteTower(tower, tools->listTower);
        }
    }	
}

void TW_CALL upgradeTowerCB(void *clientData){
	Tools *tools = (Tools *)clientData;
	foreachList(node, *tools->listTower){
		Tower *tower = (Tower *)node->data;
        if(tower->select == 1){
	        if(tower->lvl < 3){
	        	if(tools->player->money >= tower->priceUpgrade){			// si le joueur a assez d'argent pour faire un upgrade
	        		setMoneyPlayer(tools->player,-(tower->priceUpgrade));
	        		updateTowerLevel(tower, tools->player->param.w_width);
	        	}
	        	else{
	        		printf("Vous n'avez pas assez d'argent.\n");
	        	}
	        }
	        else{
	        	printf("Vous avez deja atteind le niveau maximum de la tour.\n");
	        }
        }
    }
}

void TW_CALL quitCB(void *clientData){
	int *loop = (int *)clientData;
	quit(loop);
}

void setWelcomeMenu(TwBar *bar, TwBar *ruleBar, MenuITD *menu, int *loop, int *start){
	// Ajout de la list ITD
	TwType itdName;
	// Boucle sur la liste des Itds pour créer un Enum.
	char enumeration[100] = "\0";
	foreachList(node, menu->itds){
		char *itd = (char *)node->data;
		strcat(enumeration, itd);
		if(node->next != NULL){
			strcat(enumeration, ",\0");
		}
	}
	// Créer un Enum 
	itdName = TwDefineEnumFromString("ItdName", enumeration);
	TwAddVarCB(bar, "chooseItd", itdName, setChooseITDCB, getChooseITDCB, menu," label='Choose your Itd' ");
	// Ajout du bouton Jouer
	TwAddButton(bar, "play", playCB, start, " label='Play' key='SPACE' help='Run game.' ");
	TwAddSeparator(bar, "sep1", NULL);
	// Ajout du bouton Règles
	TwAddButton(bar, "rules", ruleCB, ruleBar, " label='Rules' help='Open Rules' ");
	TwAddSeparator(bar, "sep2", NULL);
	// Ajout du bouton Quitter
	TwAddButton(bar, "quit1", quitCB, loop, " label='Quit ?' key='ESC or q' help='Quit program.' ");
}

void setLastMenu(TwBar *bar, Tools *tools){
	// Ajout du bouton Jouer
	TwAddButton(bar, "replay", replayCB, tools, " label='Replay, ce jeu est trop bien !!!' help='Replay game.' ");
	TwAddSeparator(bar, "sep1", NULL);
	// Ajout du bouton Quitter
	TwAddButton(bar, "quit1", quitCB, tools->loop, " label='Quit ?' key='ESC or q' help='Quit program.' ");
}

void setRulesMenu(TwBar *bar){
	TwAddButton(bar, "rulesComment1", NULL, NULL, " label='The goal is to prevent monsters from reaching the exit point of the path by attacking with towers.' ");
	TwAddButton(bar, "rulesComment2", NULL, NULL, " label='No action on your part a wave of monster launches automatically after 60 seconds.' ");
	TwAddButton(bar, "rulesComment3", NULL, NULL, " label='However if you feel the soul of a warrior you can choose to launch the next wave faster.' ");
	TwAddButton(bar, "rulesComment4", NULL, NULL, " label='Your goal is to survive all 20 waves stronger and stronger as each other monsters.' ");
	TwAddButton(bar, "rulesComment5", NULL, NULL, " label='To overcome this you will be able to upgrade your towers.' ");
	TwAddButton(bar, "rulesComment6", NULL, NULL, " label='There are two levels of improvement for each of four types of towers.' ");
}

void setMainMenu(TwBar *bar, int *loop, Tools *tools){
	// Ajout de Joueur.
	TwAddButton(bar, "player", NULL, NULL, " label='--- Player ---' ");
		TwAddVarRO(bar, "Life", TW_TYPE_INT32, &(tools->player->life), " label='Life' ");
		TwAddVarRO(bar, "Money (Or)", TW_TYPE_INT32, &(tools->player->money), " label='Money' ");
		TwAddVarRO(bar, "Level", TW_TYPE_INT32, &(tools->player->lvl), " label='Level' ");
	TwAddSeparator(bar, "sep1", NULL);
	// Ajout de Map.
	TwAddButton(bar, "map", NULL, NULL, " label='--- Map ---' ");
		TwAddVarRO(bar, "Wave", TW_TYPE_INT32, &(tools->player->lvl), " label='Wave' ");
		TwAddVarRO(bar, "Debug", TW_TYPE_BOOL32, &(tools->map->debug), " label='Debug' true=Yes false=No ");
		TwAddVarRO(bar, "ConstructMode", TW_TYPE_BOOL32, &(tools->player->constructMode), " label='Construct Mode' true=Yes false=No ");
	TwAddSeparator(bar, "sep2", NULL);
	// Ajout de tower.
	TwAddButton(bar, "tower", NULL, NULL, " label='--- Tower ---' ");
		// Ajout du bouton créer une tour.
		TwAddVarRO(bar, "priceRocket", TW_TYPE_INT32, &(tools->priceRocket), " label='Rocket Price' ");
		TwAddVarRO(bar, "priceHybrid", TW_TYPE_INT32, &(tools->priceHybrid), " label='Hybrid Price' ");
		TwAddVarRO(bar, "priceLaser", TW_TYPE_INT32, &(tools->priceLaser), " label='Laser Price' ");
		TwAddVarRO(bar, "priceMachineGun", TW_TYPE_INT32, &(tools->priceMachineGun), " label='MachineGun Price' ");
		TwType typeTower;
		typeTower = TwDefineEnum("typeTower", NULL, 0);
		TwAddVarCB(bar, "Create tower", typeTower, setSelectTower, getSelectTower, tools," enum='0 {None/Del}, 1 {Rocket}, 2 {Hybrid}, 3 {Laser}, 4{MachineGun}' ");
	TwAddSeparator(bar, "sep3", NULL);
	// Ajout du bouton pour Lancer la prochaine wave.
	TwAddButton(bar, "waveComment1", NULL, NULL, " label='  It is you who must manage the' ");
	TwAddButton(bar, "waveComment2", NULL, NULL, " label='launch waves of monsters.' ");
	TwAddButton(bar, "waveComment3", NULL, NULL, " label='However, you must have completed' ");
	TwAddButton(bar, "waveComment4", NULL, NULL, " label='a wave to start another. It is' ");
	TwAddButton(bar, "waveComment5", NULL, NULL, " label='convenient to prepare by placing' ");
	TwAddButton(bar, "waveComment6", NULL, NULL, " label='towers before the next wave.' ");
	TwAddButton(bar, "nextWave", nextWaveCB, tools, " label='Next Wave' key='u' help='If you are ready, launch next wave.' ");
	TwAddSeparator(bar, "sep4", NULL);
	// Ajout du bouton pour quitter.
	TwAddButton(bar, "quit2", quitCB, loop, " label='Quit ?' key='ESC' help='Quit program.' ");
}

void setTwTower(TwBar *bar, Tower *t, Tools *tools){
	TwType towerType;
	towerType = TwDefineEnum("TowerType", NULL, 0);
	TwAddVarRO(bar, "Type", towerType, &(t->type), " label='Type' enum='1 {Rocket}, 2 {Hybrid}, 3 {Laser}, 4 {MachineGun}' ");
	TwAddVarRO(bar, "Range", TW_TYPE_INT32, &(t->rangePx), " label='Range in Pixels' ");
	TwAddVarRO(bar, "Damage", TW_TYPE_INT32, &(t->damage), " label='Damages' ");
	TwAddVarRO(bar, "Cadence", TW_TYPE_INT32, &(t->cadence), " label='Cadence ' ");
	TwAddSeparator(bar, "sep7", NULL);
	TwAddVarRO(bar, "Level", TW_TYPE_INT32, &(t->lvl), " label='Tower Level ' ");
	TwAddVarRO(bar, "UpgradePrice", TW_TYPE_INT32, &(t->priceUpgrade), " label='Upgrade Price ' ");
	TwAddVarRO(bar, "Money", TW_TYPE_INT32, &(t->price), " label='Spent money' ");
	TwAddSeparator(bar, "sep5", NULL);
	TwAddButton(bar, "upgrade", upgradeTowerCB, tools, " label='Upgrade' key='y' help='Upgrade the tower' ");
	TwAddButton(bar, "delete", deleteTowerCB, tools, " label='Del' key='t' help='Delete the tower' ");
}

void setTwMonster(TwBar *bar, Monster *m, Tools *tools){
	TwType monsterType;
	monsterType = TwDefineEnum("MonsterType", NULL, 0);
	TwAddVarRO(bar, "Type", monsterType, &(m->type), " label='Type' enum='0 {Baby}, 1 {Low}, 2 {Medium}, 3 {Hard}' ");
	TwAddVarRO(bar, "Life", TW_TYPE_INT32, &(m->lifeT), " label='Life' ");
	TwAddVarRO(bar, "RemainingLife", TW_TYPE_INT32, &(m->life), " label='Remaining life' ");
	TwAddVarRO(bar, "MoneyEarn", TW_TYPE_INT32, &(m->earn), " label='Money to earn' ");
	TwAddSeparator(bar, "sep6", NULL);
	TwAddVarRO(bar, "ResisteRocket", TW_TYPE_INT32, &(m->resistRocket), " label='Resistance Rocket' ");
	TwAddVarRO(bar, "ResisteLaser", TW_TYPE_INT32, &(m->resistLaser), " label='Resistance Laser' ");
	TwAddVarRO(bar, "ResisteHybrid", TW_TYPE_INT32, &(m->resistHybrid), " label='Resistance Hybrid' ");
	TwAddVarRO(bar, "ResisteMachineGun", TW_TYPE_INT32, &(m->resistMachineGun), " label='Resistance MachineGun' ");
}